home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / nntpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-06  |  26.5 KB  |  1,200 lines

  1. /*
  2.  *
  3.  * NNTP Server - See RFC977
  4.  * Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
  5.  * Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
  6.  * Permission granted for non-commercial copying and use, provided
  7.  * this notice is retained.
  8.  *
  9.  * DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
  10.  * DB3FL 920121: splitted into several files
  11.  * DG1ZX 9210xx: bug fixing and optimize
  12.  * DG1ZX 9303xx: included POST and XDHR command
  13.  * DG1ZX 930728: included nntp restrictions and history lifetime
  14.  *
  15.  */
  16. #include <dos.h>
  17. #include <time.h>
  18. #include <ctype.h>
  19.  
  20. #include "global.h"
  21. #include "config.h"
  22. #ifdef NNTP
  23. #include "nntp.h"
  24. #include "socket.h"
  25. #include "files.h"
  26. #include "ftp.h"
  27. #include "bm.h"
  28. #ifdef LZW
  29. #include "lzw.h"
  30. #endif
  31.  
  32. #undef CONTROL                /* (not implemented yet) */
  33. #define    LINE    80
  34.  
  35. #ifdef LZW
  36. int LzwActive = 1;
  37. #endif
  38.  
  39. #ifdef POST_ENBL
  40. int postingok = 1;
  41. #endif
  42.  
  43. int fullauto = 1;
  44. unsigned short Nntpmaxcli = 3;
  45. static unsigned short Nntpsessions = 0;
  46.  
  47. static int Snntp = -1;      /* prototype socket for service */
  48.  
  49. static char artmsg[]         = " Article retrieved - ";
  50. static char debug[]        = "100 DEBUG %s\n";
  51.  
  52. #if (defined(POST_ENBL) && defined(XHEADER))
  53. static char help[]         = "100-ARTICLE  BODY  GROUP  HEAD  HELP  IHAVE  LAST  LIST\n"
  54.                   "100 NEWNEWS  NEXT  POST   QUIT  STAT  XHDR   XINFO\n";
  55. #elif (defined(POST_ENBL))
  56. static char help[]         = "100-ARTICLE  BODY     GROUP  HEAD  HELP  IHAVE  LAST\n"
  57.                   "100 LIST     NEWNEWS  NEXT   POST  QUIT  STAT   XINFO\n";
  58. #elif (defined(XHEADER))
  59. static char help[]         = "100-ARTICLE  BODY     GROUP  HEAD  HELP  IHAVE  LAST\n"
  60.                   "100 LIST     NEWNEWS  NEXT   QUIT  STAT  XHDR   XINFO\n";
  61. #else
  62. static char help[]         = "100-ARTICLE  BODY  GROUP    HEAD  HELP  IHAVE\n"
  63.                   "100 LAST     LIST  NEWNEWS  NEXT  QUIT  STAT   XINFO\n";
  64. #endif
  65.  
  66. /*
  67. static char info[]        = "100 %s Info:\n";
  68. */
  69. static char xinfo[]        = "100 No info available\n";
  70. static char noactive[]        = "100 No active newsgroups\n";
  71.  
  72. #ifdef POST_ENBL
  73. static char nnversion[]        = "20%c %s NNTP version %s ready at %s GMT (posting %s)\n";
  74. #else
  75. static char nnversion[]        = "201 %s NNTP version %s ready at %s GMT\n";
  76. #endif
  77. static char slave[]            = "202 SLAVE %s\n";
  78. static char closing[]          = "205 Closing\n";
  79. static char listarticle[]    = "211 %u %u %u%s\n";
  80. static char listgrps[]        = "215 Available newsgroups\n";
  81. static char retrieve[]         = "220 %u%s%shead and body follow\n";
  82. static char head[]             = "221 %u%s%sHead\n";
  83. #ifdef XHEADER
  84. static char extrfoll[]         = "221 %s fields follow\n";
  85. #endif
  86. static char body[]             = "222 %u%s%sBody\n";
  87. static char statistics[]       = "223 %u%s%sStatistics\n";
  88. static char sepcmd[]           = "223 %u %s%srequest text separately\n";
  89. static char newnews_t[]        = "230 New news by message id follows\n";
  90. static char transok[]        = "235 Thanks\n";
  91. #ifdef POST_ENBL
  92. static char postok[]        = "240 Article posted ok\n";
  93. #endif
  94.  
  95. static char sendart[]        = "335 Send article, end with .\n";
  96. #ifdef POST_ENBL
  97. static char sendpost[]        = "340 Send article to be posted, end with .\n";
  98. #endif
  99.  
  100. static char nogroup[]        = "411 No such newsgroup\n";
  101. static char noselect[]        = "412 No newsgroup selected\n";
  102. static char nonext[]        = "421 No next article\n";
  103. static char noprev[]        = "422 No previous article\n";
  104. static char noart[]        = "430 No such article\n";
  105. static char notwanted[]        = "435 Article not wanted - do not send it\n";
  106. static char transnotok[]    = "437 Article rejected - do not try again\n";
  107. #ifdef POST_ENBL
  108. static char noposting[]        = "440 Posting not allowed\n";
  109. static char postfailed[]    = "441 Posting failed\n";
  110. #endif
  111. static char badsyntax[]        = "501 Syntax error\n";
  112. #if (defined(NNTPRESTRICT) || defined(NNTPLIFETIME))
  113. static char restriction[]    = "502 Access restriction\n";
  114. #endif
  115. static char error[]        = "503 Command not performed\n";
  116. static char lowmem[]        = "503 System overloaded\n";
  117. char NEol[]            = ".\n";
  118.  
  119. /* some prototypes */
  120. static int near
  121. #ifdef POST_ENBL
  122. get_article2(struct nntpsv *mp, int command);
  123. #else
  124. get_article2(struct nntpsv *mp);
  125. #endif
  126.  
  127.  
  128.  
  129. static int near
  130. strxlen(register char *s)
  131. {
  132.     register int i = 0;
  133.  
  134.     while(*s++ != '\0')
  135.         i++;
  136.     return i;
  137. }
  138.  
  139. /* main message-opening routine
  140.  * returncode: NULLFILE if error; filepointer success */
  141. static FILE * near
  142. open_message(struct nntpsv *mp,FILE *f)
  143. {
  144.     char line[LineLen];
  145.  
  146.     if(f != NULLFILE)
  147.         fclose(f);
  148.  
  149.     sprintf(line,"%s/%u",mp->path,mp->pointer);
  150.  
  151.     if ((f = fopen(line,READ_TEXT)) == NULLFILE)
  152.         usputs(mp->s,noart);
  153.     return f;
  154. }
  155.  
  156. /* returncode: -1 error; 1 success; 0 no entry */
  157. static int near
  158. get_path(char *group,struct nntpsv *mp)
  159. {
  160.     FILE *f;
  161.     char line[LineLen], *cp;
  162.  
  163.     if(group == NULLCHAR || mp == NULLNNTPSV
  164.       || (f = open_file(Pointer,READ_TEXT,mp->s,0)) == NULLFILE)
  165.         return -1;
  166.  
  167.     group++;
  168.  
  169.     for (;;) {
  170.         if (fgets(line,LineLen,f) == NULL)
  171.             break;
  172.         if (strcspn(line," ") != strxlen(group))
  173.             continue;
  174.         if (strnicmp(group,line,strxlen(group)) == 0) {
  175.             cp = (strchr(line,' ')) + 1;
  176.             if (mp->path != NULLCHAR)
  177.                 xfree(mp->path);
  178.             mp->path = strxdup(cp);
  179.             rip2(mp->path);
  180.             fclose(f);
  181.             return 1;
  182.         }
  183.     }
  184.     fclose(f);
  185.     return 0;
  186. }
  187.  
  188. /* returncode: -1 if error; 1 success; 0 no pointer */
  189. static int near
  190. get_pointer(char *group,struct nntpsv *mp)
  191. {
  192.     FILE *f;
  193.     char line[LineLen], *p;
  194.  
  195.     if(group == NULLCHAR || mp == NULLNNTPSV
  196.       || (f = open_file(Active,READ_TEXT,mp->s,0)) == NULLFILE)
  197.         return -1;
  198.  
  199.     group++;
  200.  
  201.     for (;;) {
  202.         if (fgets(line,LineLen,f) == NULL)
  203.             break;
  204.         if (strcspn(line," ") != strxlen(group))
  205.             continue;
  206.         if (strnicmp(group,line,strxlen(group))==0) {
  207.             p = strchr(line,' ');
  208.             mp->last = (unsigned)atoi(p);
  209.             mp->first = (unsigned)atoi(strchr(++p,' '));
  210.             mp->pointer = (mp->first > mp->last ) ? 0 : mp->first;
  211.             fclose(f);
  212.             return 1;
  213.         }
  214.     }
  215.     fclose(f);
  216.     return 0;
  217. }
  218.  
  219. #ifdef CONTROL
  220. static int near
  221. docontrol(FILE *f,struct nntpsv *mp)
  222. {
  223.     struct head *h;
  224.  
  225.     if(f == NULLFILE || mp == NULLNNTPSV
  226.       || (h = (struct head *)mxallocw(sizeof(struct head))) == NULLHEAD))
  227.         return -1;
  228.  
  229.     rewind(f);
  230.     h->subject = h->from = h->reply_to = h->id = NULLCHAR;
  231.  
  232.     for(;;) {
  233.         if ((fgets(mp->buf,LineLen,f)) == NULL)
  234.             break;
  235.         if (check_blank(mp->buf))
  236.             break;
  237.         rip2(mp->buf);
  238.         if (strncmp(mp->buf,subj,9) == 0)
  239.             h->subject = strxdup(mp->buf);
  240.         if (strncmp(mp->buf,frm,6) == 0)
  241.             h->from = strxdup(mp->buf);
  242.         if (strnicmp(mp->buf,reply_to,10) == 0)
  243.             h->reply_to = strxdup(mp->buf);
  244.         if (strnicmp(mp->buf,msgid,12) == 0)
  245.             h->id = strxdup(strchr(mp->buf,'<'));
  246.     }
  247.     if (h->subject != NULLCHAR)
  248.         if (strncmp(h->subject,"Subject: sendme ",16) == 0)
  249.             dosendme(h);
  250.     if (h->subject != NULLCHAR)
  251.         xfree(h->subject);
  252.     if (h->from != NULLCHAR)
  253.         xfree(h->from);
  254.     if (h->reply_to != NULLCHAR)
  255.         xfree(h->reply_to);
  256.     if (h->id != NULLCHAR)
  257.         xfree(h->id);
  258.     xfree((char *)h);
  259.     return 0;
  260. }
  261. #endif
  262.  
  263.  
  264. /***********************************/
  265. /* handles incoming newnews-cmd    */
  266. /***********************************/
  267.  
  268. static void near
  269. donewnews(char *string,struct nntpsv *mp)
  270. {
  271.     FILE *f;
  272.  
  273.     if((f = temp_file(mp->s,1)) == NULLFILE)
  274.         return;
  275.  
  276. #if (defined(NNTPRESTRICT) || defined(NNTPLIFETIME))
  277.     switch(newnews(string,mp,f,1)) {
  278. #else
  279.     switch(newnews(string,mp,f)) {
  280. #endif
  281.  
  282. #ifdef NNTPLIFETIME
  283.     case -3:        /* user request with unaccept poll date/time */
  284. #endif
  285. #ifdef NNTPRESTRICT
  286.     case -2:        /* user request: ALL newsgroups */
  287. #endif
  288. #if (defined(NNTPRESTRICT) || defined(NNTPLIFETIME))
  289.         usputs(mp->s,restriction);
  290.         break;
  291. #endif
  292.     case -1:        /* error in "newnews" routine */
  293.         usputs(mp->s,badsyntax);
  294.         break;
  295.     case 0:                 /* no new news */
  296.         usputs(mp->s,newnews_t);
  297.         usputs(mp->s,NEol);
  298.         break;
  299.     default:        /* new news available, send news file */
  300.         usputs(mp->s,newnews_t);
  301.         sendfile(f,mp->s,ASCII_TYPE,0);
  302.         usputs(mp->s,NEol);
  303.         break;
  304.     }
  305.     fclose(f);
  306.     return;
  307. }
  308.  
  309. /* change current newsgroup
  310.  * returncode: -1 if error; 0 success; 1 no newsgroup */
  311. static int near
  312. dogroup(struct nntpsv *mp,char *buf)
  313. {
  314.     char *p;
  315.     int er = -1;
  316.  
  317.     if((p = strchr(buf,' ')) == NULLCHAR)
  318.         return er;
  319.  
  320.     switch (er = get_path(p,mp)) {
  321.     case 0:
  322.         usputs(mp->s,nogroup);
  323.         er = 1;
  324.         break;
  325.     default:
  326.         p = strchr(buf,' ');
  327.         if (get_pointer(p,mp) == 1) {
  328.             usprintf(mp->s,listarticle,
  329.                 mp->last - mp->first + 1,mp->first,mp->last,strchr(buf,' '));
  330.             return 0;
  331.         }
  332.     case -1:
  333.         usputs(mp->s,error);
  334.         break;
  335.     }
  336.     return er;
  337. }
  338.  
  339.  
  340. /* checks if newsgroup is selected
  341.  * returncode: -1 no group selected; 0 success */
  342. static int near
  343. check_grp(struct nntpsv *mp)
  344. {
  345.     if(mp == NULLNNTPSV || mp->path == NULLCHAR) {
  346.         usputs(mp->s,noselect);
  347.         return -1;
  348.     }
  349.     return 0;
  350. }
  351.  
  352. /* get id-number of message
  353.  * returncode: -1 if error; 0 if no message; 1 success */
  354. static int near
  355. get_id(char *bp,struct nntpsv *mp)
  356. {
  357.     FILE *f;
  358.     char tmp[LineLen];
  359.  
  360.     if ((f = open_message(mp,NULLFILE)) == NULLFILE)
  361.         return 0;
  362.  
  363.     for (;;) {
  364.         if (fgets(tmp,LineLen,f) == NULL)
  365.             break;
  366.         if (check_blank(tmp))
  367.             break;
  368.         if (strnicmp(tmp,msgid,12)==0) {
  369.             fclose(f);
  370.             strcpy(bp,strchr(tmp,' '));
  371.             rip2(bp);
  372.             return 1;
  373.         }
  374.     }
  375.     fclose(f);
  376.     strcpy(bp,"\0");
  377.     return 0;
  378. }
  379.  
  380. /* gets next news of newsgroup
  381.  * returncode: -1 if error; 0 no news; 1 success */
  382. static int near
  383. get_next(struct nntpsv *mp)
  384. {
  385.     FILE *f;
  386.  
  387.     for (;;) {
  388.         if (mp->pointer == 0 ) {
  389.             usputs(mp->s,nonext);
  390.             return 0;
  391.         }
  392.         if (++(mp->pointer) > mp->last) {
  393.             mp->pointer--;
  394.             usputs(mp->s,nonext);
  395.             return 0;
  396.         }
  397.         sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  398.         if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  399.             fclose(f);
  400.             return 1;
  401.         }
  402.     }
  403. }
  404.  
  405. /* gets last news of newsgroup
  406.  * returncode: -1 if error; 0 no news; 1 success */
  407. static int near
  408. get_last(struct nntpsv *mp)
  409. {
  410.     FILE *f;
  411.  
  412.     for (;;) {
  413.         if (mp->pointer == 0) {
  414.             usputs(mp->s,noprev);
  415.             return 0;
  416.         }
  417.         if (--(mp->pointer) < mp->first) {
  418.             mp->pointer++;
  419.             usputs(mp->s,noprev);
  420.             return 0;
  421.         }
  422.         sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  423.         if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  424.             fclose(f);
  425.             return 1;
  426.         }
  427.     }
  428. }
  429.  
  430. static int near
  431. art_ret(struct nntpsv *mp,char flag)
  432. {
  433.     if(get_id(mp->buf,mp) < 1)
  434.         return -1;
  435.     if(flag)
  436.         usprintf(mp->s,retrieve,mp->pointer,mp->buf,artmsg);
  437.     return 0;
  438. }
  439.  
  440. /* Sends article <message-id> to the client or check if host in path
  441.  * we are polling now, already exists.
  442.  * Return value: -1 on error, 1 article sent, 0 no article
  443.  * flag  = 1 : check only pathfield in article
  444.  * flag  = 0 : send article
  445.  */
  446. int
  447. doarticle(char *buf,struct nntpsv *mp,char flag, char *hname)
  448. {
  449.     FILE *f;
  450.     char *p, *p2, *holds, line[LineLen];
  451.     int32 ok = 0;
  452.  
  453.     if((p = strchr(buf,'<')) == NULLCHAR
  454.      || (f = fopen(History,READ_TEXT)) == NULLFILE) {
  455.         usputs(mp->s,badsyntax);
  456.         return -1;
  457.     }
  458.     while(fgets(line,LineLen,f),!feof(f)) {
  459.         if (strstr(line,p) != NULLCHAR) {
  460.             fclose(f);
  461.             p = (strchr(line,' ')) + 14;      /* pointer to the first newsgroup */
  462.             p2 = strchr(p,'/');                  /* pointer to article number */
  463.             mp->hold_i = mp->pointer;       /* save current pointer */
  464.             holds = strxdup(mp->path);       /* save path of current article */
  465.             mp->pointer = atoi((p2 + 1));     /* get the article number */
  466.  
  467.             if (mp->path != NULLCHAR) {
  468.                 xfree(mp->path);
  469.                 mp->path='\0';
  470.             }
  471.  
  472.             *p2 = '\0';
  473.             rip2(p);
  474.  
  475.             if (strncmp(p+1,"JUNK",6) == 0) {
  476.                 sprintf(mp->buf,"%s",Forward);
  477.                 mp->path = strxdup(mp->buf);
  478.             } else
  479.                 get_path(p,mp);
  480.  
  481.             if(hname == NULLCHAR ) {
  482.                 /* send article */
  483.                 if ((f = open_message(mp,f)) == NULLFILE) {
  484.                     xfree(mp->path);        /* file not found */
  485.                     mp->path = strxdup(holds);
  486.                     mp->pointer = mp->hold_i;
  487.                     xfree(holds);
  488.                     return -1;
  489.                 }
  490.                 if(art_ret(mp,flag) != -1) {
  491.                     ok = sendfile(f, mp->s, ASCII_TYPE,0);
  492.                     ok = (ok == -1) ? -1 : 1;
  493.                     usputs(mp->s,NEol);
  494.                 }
  495.             }
  496.             else { int getpath = 0;
  497.                 /* check only pathfield in article */
  498.                 sprintf(line,"%s/%u",mp->path,mp->pointer);
  499.                 if ((f = fopen(line,READ_TEXT)) == NULLFILE) {
  500.                     xfree(mp->path);        /* file not found */
  501.                     mp->path = strxdup(holds);
  502.                     mp->pointer = mp->hold_i;
  503.                     xfree(holds);
  504.                     return -1;
  505.                 }
  506.  
  507.                 while (!getpath && (fgets(line,LINELEN,f),!feof(f))){
  508.                     if (strnicmp(line,pth,6) != 0)
  509.                         continue;
  510.                     ok = 1;            /* default: send article */
  511.                     getpath = 1;    /* reset condition for while-loop */
  512.  
  513.                     /* skip first entry, because its our own hostname */
  514.                     p2 = strstr(line,"!") + 1;
  515.  
  516.                     for (;;) {
  517.                         /* cut off first entry and compare it with the hostname */
  518.                         if ((p = strstr(p2,"!")) == NULL)
  519.                             break;
  520.                         *p='\0';
  521.                         if (strcmpi(hname,p2) == 0) {
  522.                             ok = 0;        /* oops, I've got you. */
  523.                             break;        /* don't forward article */
  524.                         }
  525.                         p2 = ++p;
  526.                     }
  527.                 }
  528.             }
  529.             fclose(f);
  530.             xfree(mp->path);
  531.             mp->path = strxdup(holds);
  532.             mp->pointer = mp->hold_i;
  533.             xfree(holds);
  534.             return ((int)ok);
  535.         }
  536.     }
  537.     fclose(f);
  538.     usputs(mp->s,noart);
  539.     return 0;
  540. }
  541.  
  542.  
  543. static int near
  544. set_pointer(struct nntpsv *mp, char *buf)
  545. {
  546.     char *cp;
  547.  
  548.     if((cp = strpbrk(buf,"0123456789")) != NULLCHAR) {
  549.         int cnt = atoi(cp);
  550.         if ((cnt > mp->last) || ( cnt < mp->first)) {
  551.             usputs(mp->s,noart);
  552.             return -1;
  553.         }
  554.         mp->pointer = cnt;
  555.     }
  556.     return 0;
  557. }
  558.  
  559. static void
  560. nntpserv(int s, void *unused, void *p) {
  561.     struct nntpsv *mp;
  562.     struct    tm *ltm;
  563.     FILE *fp;
  564.     long t;
  565.     int cnt;
  566.     char **cmdp, *arg, *cp, *cmd, buf[LineLen];
  567. #ifdef LZW
  568.     int lbits, lmode;
  569. #endif
  570. #ifdef XHEADER
  571.     char *cp2;
  572.     int first, last;
  573. #endif
  574.  
  575.     /* Command table */
  576.     char *commands[] = {
  577.         "quit",
  578. #define QUIT_CMD    0
  579.         "help",
  580. #define HELP_CMD    1
  581.         "list",
  582. #define LIST_CMD    2
  583.         "group",
  584. #define GROUP_CMD    3
  585.         "debug",
  586. #define DEBUG_CMD    4
  587.         "article",
  588. #define ARTICLE_CMD    5
  589.         "next",
  590. #define NEXT_CMD    6
  591.         "xinfo",
  592. #define XINFO_CMD    7
  593.         "ihave",
  594. #define IHAVE_CMD    8
  595.         "newnews",
  596. #define NEWNEWS_CMD    9
  597.         "head",
  598. #define HEAD_CMD    10
  599.         "body",
  600. #define BODY_CMD    11
  601.         "stat",
  602. #define STAT_CMD    12
  603.         "last",
  604. #define LAST_CMD    13
  605.         "slave",
  606. #define SLAVE_CMD    14
  607.         "xlzw",
  608. #define XLZW_CMD    15
  609.  
  610. #if (defined(XHEADER) && defined(POST_ENBL))
  611.         "post",
  612. #define POST_CMD    16
  613.         "xhdr",
  614. #define XHDR_CMD    17
  615.  
  616. #elif (defined(XHEADER))
  617.         "xhdr",
  618. #define XHDR_CMD    16
  619.  
  620. #elif (defined(POST_ENBL))
  621.         "post",
  622. #define POST_CMD    16
  623.  
  624. #endif
  625.         NULLCHAR
  626.     };
  627.  
  628.     sockmode(s,SOCK_ASCII);
  629.     sockowner(s,Curproc);        /* We own it now */
  630.  
  631.     if (!Filecheck)
  632.         if(check_system()) {
  633.             usprintf(s,fatal,"STRUCTURE");
  634.             close_s(s);
  635.             return;
  636.         }
  637.  
  638.     if((mp = (struct nntpsv *)mxallocw(sizeof(struct nntpsv))) == NULLNNTPSV) {
  639.         usprintf(s,Nospace);
  640.         close_s(s);
  641.         return;
  642.     }
  643.     mp->s = s;
  644.     log(mp->s,"NNTP open");
  645.     mp->debug = 0;
  646.     mp->id = mp->path = mp->newnews = NULLCHAR;
  647.  
  648.     time(&t);
  649.     ltm = gmtime(&t);
  650.     cp = asctime(ltm);        /* nntp time always GMT */
  651.     cp[24] = '\0';
  652.  
  653.  
  654.  
  655. #ifdef POST_ENBL
  656.     usprintf(mp->s,nnversion,postingok ? '0' : '1', Hostname,Version,cp,
  657.     postingok ? "ok" : "not allowed");
  658. #else
  659.     usprintf(mp->s,nnversion,Hostname,Version,cp);
  660. #endif
  661.  
  662.     if(++Nntpsessions > Nntpmaxcli) {
  663.         usputs(mp->s,lowmem);
  664.         goto quit;
  665.     }
  666.  
  667. loop:
  668.     if ((cnt = recvline(mp->s,buf,LineLen)) == -1) {
  669.         /* He closed on us */
  670.         goto quit;
  671.     }
  672.     rip2(buf);
  673.     cmd = buf;
  674.  
  675.     /* Translate entire buffer to lower case */
  676.     for(cp = cmd; *cp != '\0' && *cp != ' ' ;cp++) {
  677.         *cp = tolower(*cp);
  678.     }
  679.     /* Find command in table; if not present, return syntax error */
  680.     for(cmdp = commands; *cmdp != NULLCHAR; cmdp++)
  681.         if(strnicmp(*cmdp,cmd,strxlen(*cmdp)) == 0)
  682.             break;
  683.  
  684.     if(*cmdp == NULLCHAR){
  685.         usputs(mp->s,badsyntax);
  686.         goto loop;
  687.     }
  688.     arg = &cmd[strxlen(*cmdp)];
  689.  
  690.     /* Skip spaces after command */
  691.     while(*arg == ' ')
  692.         arg++;
  693.  
  694.     /* Execute specific command */
  695.     switch((int)(cmdp - commands)) {
  696.     case XLZW_CMD:
  697. #ifdef LZW
  698.         if (LzwActive)   {
  699.                usprintf(mp->s,transok);
  700.                cp = strchr(arg,' ');
  701.                    *cp++ = '\0';
  702.                lbits = atoi(arg); /*get lzwbits*/
  703.                lmode = atoi(cp);
  704.                lzwinit(mp->s,lbits,lmode);
  705.         } else
  706. #endif
  707.         usprintf(mp->s,error);
  708.         break;
  709.     case QUIT_CMD:
  710.         usputs(mp->s,closing);
  711.         goto quit;
  712.     case NEWNEWS_CMD:
  713.         if ((cp = strchr(buf,' ')) == NULLCHAR)
  714.             usputs(mp->s,badsyntax);
  715.         else
  716.             donewnews(++cp,mp);
  717.         break;
  718.     case IHAVE_CMD:
  719.         if ((cp = strchr(buf,'<')) == NULLCHAR)
  720.             usputs(mp->s,badsyntax);
  721.         else if (check_article(cp) == 1)
  722.             usputs(mp->s,notwanted);
  723.         else {
  724.             usputs(mp->s,sendart);
  725. #ifdef POST_ENBL
  726.             get_article2(mp,IHAVE_CMD);
  727. #else
  728.             get_article2(mp);
  729. #endif
  730.         }
  731.         break;
  732. #ifdef POST_ENBL
  733.     case POST_CMD :
  734.         if (postingok) {
  735.             usputs(mp->s,sendpost);
  736.             get_article2(mp,POST_CMD);
  737.         }
  738.         else
  739.             usputs(mp->s,noposting);
  740.         break;
  741. #endif
  742.     case HELP_CMD:
  743.         usprintf(mp->s,"100-%s - help follows\n",Hostname);
  744.         if ((fp = fopen(Nhelp,READ_TEXT)) != NULLFILE ) {
  745.             sendfile(fp,mp->s,ASCII_TYPE,0);
  746.             fclose(fp);
  747.         } else
  748.             usputs(mp->s,help);
  749.         usputs(mp->s,NEol);
  750.         break;
  751.     case XINFO_CMD:
  752.         if ((fp = fopen(NInfo,READ_TEXT)) != NULLFILE ) {
  753.             usprintf(mp->s,"100-%s - info follows\n",Hostname);
  754.             sendfile(fp,mp->s,ASCII_TYPE,0);
  755.             fclose(fp);
  756.         } else
  757.             usputs(mp->s,xinfo);
  758.         usputs(mp->s,NEol);
  759.         break;
  760.     case LIST_CMD:
  761.         if ((fp = open_file(Active,READ_TEXT,mp->s,0)) != NULLFILE) {
  762.             usputs(mp->s,listgrps);
  763.             sendfile(fp,mp->s,ASCII_TYPE,0);
  764.             fclose(fp);
  765.             usputs(mp->s,NEol);
  766.         } else
  767.             usputs(mp->s,noactive);
  768.         break;
  769.     case GROUP_CMD :
  770.         if(dogroup(mp,&buf[0]) == -1)
  771.             usputs(mp->s,badsyntax);
  772.         break;
  773.     case HEAD_CMD :
  774.         if (check_grp(mp))
  775.             break;
  776.         if(set_pointer(mp,buf))
  777.             break;
  778.         if (get_id(mp->buf,mp) == 0)
  779.             break;
  780.         usprintf(mp->s,head,mp->pointer,mp->buf,artmsg);
  781.         if ((fp = open_message(mp,fp)) != NULLFILE) {
  782.             for (;;) {
  783.                 if ((fgets(mp->buf,LineLen,fp)) == NULL)
  784.                     break;
  785.                 if (check_blank(mp->buf))
  786.                     break;
  787.                 usputs(mp->s,mp->buf);
  788.             }
  789.             fclose(fp);
  790.         }
  791.         usputs(mp->s,NEol);
  792.         break;
  793.     case BODY_CMD :
  794.         if (check_grp(mp))
  795.             break;
  796.         if(set_pointer(mp,buf))
  797.             break;
  798.         if (get_id(mp->buf,mp) == 0)
  799.             break;
  800.         usprintf(mp->s,body,mp->pointer,mp->buf,artmsg);
  801.         if ((fp = open_message(mp,fp)) != NULLFILE) {
  802.             mp->hold_i = 0;
  803.             for (;;) {
  804.                 if ((fgets(mp->buf,LineLen,fp)) == NULL)
  805.                     break;
  806.                 if (mp->hold_i)
  807.                     usputs(mp->s,mp->buf);
  808.                 if (check_blank(mp->buf))
  809.                     mp->hold_i = 1;
  810.             }
  811.             fclose(fp);
  812.         }
  813.         usputs(mp->s,NEol);
  814.         break;
  815.     case STAT_CMD :
  816.         if (check_grp(mp))
  817.             break;
  818.         if(set_pointer(mp,buf))
  819.             break;
  820.         if (get_id(mp->buf,mp) == 0)
  821.             break;
  822.         usprintf(mp->s,statistics,mp->pointer,mp->buf,artmsg);
  823.         break;
  824.     case ARTICLE_CMD :
  825.         if (strchr(buf,'<') != NULLCHAR) {
  826.           doarticle(buf,mp,1,NULLCHAR);
  827.           break;
  828.         }
  829.         if (check_grp(mp))
  830.             break;
  831.         cp = strchr(buf,'e') + 1;
  832.  
  833.         if ((cnt > 8) && !(check_blank(cp))) {
  834.             if(set_pointer(mp,buf))
  835.                 break;
  836.         }
  837.         if ((fp = open_message(mp,fp)) != NULLFILE) {
  838.             art_ret(mp,1);
  839.             sendfile(fp,mp->s,ASCII_TYPE,0);
  840.             fclose(fp);
  841.             usputs(mp->s,NEol);
  842.         }
  843.         break;
  844.     case NEXT_CMD :
  845.         if (check_grp(mp))
  846.             break;
  847.         if (get_next(mp) == 1) {
  848.             if (get_id(buf,mp) == 1)
  849.                 usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  850.             break;
  851.         }
  852.         break;
  853.     case LAST_CMD :
  854.         if (check_grp(mp))
  855.             break;
  856.         if (get_last(mp) == 1 ) {
  857.             if (get_id(buf,mp) == 1)
  858.                 usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  859.             break;
  860.         }
  861.         break;
  862. #ifdef XHEADER
  863.     case XHDR_CMD:
  864.  
  865.         /* test if group is selected */
  866.         if (check_grp(mp))
  867.           break;
  868.  
  869.         /* set pointer to headerfield */
  870.         if ( (cp = strchr(buf,' ')) == NULLCHAR) {
  871.           usputs(mp->s,badsyntax);
  872.           break;
  873.         }
  874.  
  875.         /* set pointer to article range */
  876.         if ( (cp2 = strchr(++cp,' ')) == NULLCHAR)
  877.           /* no article range specified */
  878.           first = last = mp->pointer;
  879.         else {
  880.           *cp2++ = '\0';
  881.           /* get first article number */
  882.           if (!isdigit(*cp2)) {
  883.             usputs(mp->s,badsyntax);
  884.             break;
  885.           }
  886.           else
  887.             first = atoi(cp2);
  888.  
  889.           if (first < mp->first)
  890.             first = mp->first;
  891.           else {
  892.             if (first > mp->last)
  893.               first = mp->last;
  894.           }
  895.  
  896.  
  897.           /* get last number */
  898.           if ((cp2 = strchr(cp2,'-')) == NULLCHAR)
  899.             last = first;
  900.           else {
  901.             if (!isdigit(*(++cp2)))
  902.               last = mp->last;
  903.             else
  904.               last = ( (cnt = atoi(cp2)) > mp->last) ? mp->last : cnt;
  905.           }
  906.         }
  907.  
  908.         if (last < first)
  909.           last = first;
  910.  
  911.         /* send response */
  912.         usprintf(mp->s,extrfoll,strupr(cp));
  913.  
  914.         /* add a colon to headerfield */
  915.         cp = strcat(cp,":");
  916.  
  917.         /* now we are looking for headerfield in specified articlerange */
  918.         for (cnt = first; cnt <= last; cnt++) {
  919.           char line[LineLen];
  920.  
  921.           mp->pointer = cnt;
  922.           sprintf(line,"%s/%u",mp->path,mp->pointer);
  923.           if ( (fp = fopen(line,READ_TEXT)) == NULLFILE)
  924.             continue;
  925.           for (;;) {
  926.             if ((fgets(mp->buf,LineLen,fp)) == NULL)
  927.               break;
  928.             if (check_blank(mp->buf)) {
  929.               usprintf(mp->s,"%d (none)\n",cnt);
  930.               break;
  931.             }
  932.             if (strncmpi(cp,mp->buf,strlen(cp)) == NULL) {
  933.               cp2 = strchr(mp->buf,':') + 1;
  934.               *cp2++ = '\0';
  935.               usprintf(mp->s,"%d %s",cnt,cp2);
  936.               break;
  937.             }
  938.           }
  939.           fclose(fp);
  940.         }
  941.         usputs(mp->s,NEol);
  942.         break;
  943. #endif
  944.     /* This two following cmds currently are not used for much */
  945.     case DEBUG_CMD:
  946.         mp->debug = (mp->debug == 0) ? 1 : 0;
  947.         usprintf(mp->s,debug,(mp->debug == 0) ? "OFF" : "ON");
  948.         break;
  949.     case SLAVE_CMD :
  950.         mp->slave = (mp->slave == 0) ? 1 : 0;
  951.         usprintf(mp->s,slave,(mp->slave == 0) ? "OFF" : "ON");
  952.         break;
  953.     }
  954.     goto loop;
  955.  
  956. quit:
  957.  
  958.     log(mp->s,"NNTP close");
  959.     close_s(s);
  960.  
  961.     Nntpsessions--;
  962.  
  963.     if(mp->path != NULLCHAR)
  964.         xfree(mp->path);
  965.     if(mp->newnews != NULLCHAR)
  966.         xfree(mp->newnews);
  967.     xfree(mp);
  968. }
  969.  
  970.  
  971. /* returncode: -1 if error; 0 success */
  972. static int near
  973. #ifdef POST_ENBL
  974. get_article2(struct nntpsv *mp, int command)
  975. #else
  976. get_article2(struct nntpsv *mp)
  977. #endif
  978. {
  979.     FILE *f;
  980.     int  ret = -1;
  981.  
  982.     if(mp == NULLNNTPSV || (f = temp_file(0,1)) == NULLFILE)
  983.         return -1;
  984.  
  985.     if(recv_file(f,mp->s) != -1) {
  986.         char *cp;
  987.         int foundmid = 0;
  988.  
  989.         /* get id-number from article, not from IHAVE offer */
  990.         rewind(f);
  991.         while(fgets(mp->buf,LineLen,f),!feof(f)) {
  992.             rip2(mp->buf);
  993.             if (strnicmp(mp->buf,msgid,12) == 0) {
  994.                 if ((cp = strchr(mp->buf,'<')) != NULLCHAR) {
  995.                     mp->id = strxdup(cp);
  996.                     foundmid = 1;
  997.                     break;
  998.                 }
  999.             }
  1000.         }
  1001.         /* minimum header in article required !
  1002.            Now check again, if same news exists in history */
  1003.         if (foundmid == 1 && check_article(mp->id) == 0 && garbled(f) == 0) {
  1004.             rewind(f);
  1005.             ret = xfer_article2(f,mp);
  1006.         }
  1007.         else if (foundmid) {
  1008.             xfree(mp->id);
  1009.         }
  1010.     }
  1011.     fclose(f);
  1012. #ifdef POST_ENBL
  1013.     if (command == POST_CMD)
  1014.         usputs(mp->s,ret ? postfailed : postok);
  1015.     else
  1016.         usputs(mp->s,ret ? transnotok : transok);
  1017. #else
  1018.     usputs(mp->s,ret ? transnotok : transok);
  1019. #endif
  1020.     return ret;
  1021. }
  1022.  
  1023.  
  1024. /* ---------------------------- SMTP->NNTP-GATE --------------------------- */
  1025. int
  1026. nnGpost(FILE *data,char *from,struct list *le)
  1027. {
  1028.     FILE *f;
  1029.     struct nntpsv *mp;
  1030.     int msgidfound = 0;
  1031.     char buf[LineLen], *cp, *cp1, *cp2, *revpath;
  1032.  
  1033.     if (!Filecheck)
  1034.         if(check_system())
  1035.             return -1;
  1036.  
  1037.     if ((f = temp_file(0,1)) == NULLFILE)
  1038.         return -1;
  1039.  
  1040.     mp = (struct nntpsv *)mxallocw(sizeof(struct nntpsv));
  1041.  
  1042.     /* build path field (dg1zx) */
  1043.  
  1044.     /* cp is used to generate FROM field */
  1045.     cp = strxdup(from);
  1046.     if((cp1 = strpbrk(cp,"@. ")) != NULLCHAR)
  1047.         *cp1 = '\0';
  1048.  
  1049.     /* cp2 is used to copy reverse path */
  1050.     cp2 = strxdup(cp);
  1051.     revpath = mxallocw(strlen(cp2)+1);
  1052.     *revpath = '\0';
  1053.  
  1054.     while ((cp1 = strrchr(cp2,'%')) != NULL) {
  1055.         *cp1++ = '\0';
  1056.         strcat(revpath,cp1);
  1057.         strcat(revpath,"!");
  1058.     }
  1059.  
  1060.     strcat(revpath,cp2);
  1061.     fprintf(f,"%s%s\n",pth,revpath);
  1062.  
  1063.     xfree(revpath);
  1064.     xfree(cp2);
  1065.  
  1066.  
  1067.     /* look for msg-id */
  1068.     rewind(data);
  1069.     while(fgets(buf,LineLen,data) != NULL)   {
  1070.         if(*buf == '\t' || *buf == ' ')
  1071.             continue;
  1072.         rip(buf);
  1073.         if(*buf == '\0')
  1074.             break;
  1075.         if(htype(buf) == MSGID) {
  1076.             msgidfound = 1;
  1077.             break;
  1078.         }
  1079.     }
  1080.  
  1081.     /* reorganize header */
  1082.     rewind (data);
  1083.     while(fgets(buf,LineLen,data) != NULL)   {
  1084.         if(*buf == '\t' || *buf == ' ')
  1085.             continue;
  1086.         rip(buf);
  1087.         if(*buf == '\0')
  1088.             break;
  1089.         switch(htype(buf)) {
  1090.         case FROM:
  1091.             /* generating from line */
  1092.             fprintf(f,"%s%s@%s",frm,cp,Hostname);
  1093.             if((cp1 = strpbrk(buf,"<(")) != NULLCHAR)
  1094.                 fprintf(f," %s",cp1);
  1095.  
  1096.             /* generating newsgroups line */
  1097.             if((cp1 = strpbrk(&le->val[1],"!@")) != NULLCHAR)
  1098.                 *cp1 = '\0';
  1099.             fprintf(f,"\n%s%s\n",ngrps,&le->val[1]);     /* skip the bang */
  1100.             continue;
  1101.         case SUBJECT:
  1102.             fprintf(f,"%s\n",strxlen(buf) < 10 ? "Subject: (none)" : buf);
  1103.             if(msgidfound == 0) {
  1104.  
  1105.             sprintf(mp->buf,"<%ld@%s>",get_msgid(),Hostname);
  1106.                 fprintf(f,"%s%s\n",msgid,mp->buf);
  1107.                 mp->id = strxdup(mp->buf);
  1108.             }
  1109.             fprintf(f,"Sender: NNTP@%s\n",Hostname);
  1110.             continue;
  1111.         case MSGID:
  1112.             if(msgidfound == 1) {
  1113.                 fprintf(f,"%s\n",buf);
  1114.                 if((cp1 = strchr(buf,'<')) != NULLCHAR) {
  1115.                     sprintf(mp->buf,"%s",cp1);
  1116.                     mp->id = strxdup(cp1);
  1117.                 }
  1118.             }
  1119.             continue;
  1120.         case TO:
  1121.         case RECEIVED:
  1122.         case SENDER:
  1123.         case STATUS:
  1124.         case NOHEADER:
  1125.             continue;
  1126.         }
  1127.         fprintf(f,"%s\n",buf);
  1128.     }
  1129.  
  1130.     xfree(cp);
  1131.  
  1132.     fputc('\n',f);
  1133.  
  1134.     while(fgets(buf,sizeof(buf),data) != NULL)
  1135.         fputs(buf,f);
  1136.  
  1137.     fflush(f);
  1138.     rewind(f);
  1139.     xfer_article2(f,mp);
  1140.     fclose(f);
  1141.     xfree(mp);
  1142.     return 0;
  1143. }
  1144.  
  1145. /* ---------------------------- Servercmd --------------------------- */
  1146.  
  1147. /* Start up NNTP receiver service */
  1148. int
  1149. nntp1(argc,argv,p)
  1150. int argc;
  1151. char *argv[];
  1152. void *p;
  1153. {
  1154.     struct sockaddr_in lsocket;
  1155.     int s;
  1156.  
  1157.     if(Snntp != -1 || check_system() == -1)
  1158.         return -1;
  1159.  
  1160.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  1161.     chname(Curproc,"NNTP listener");
  1162.  
  1163.     lsocket.sin_family = AF_INET;
  1164.     lsocket.sin_addr.s_addr = INADDR_ANY;
  1165.     lsocket.sin_port = (argc < 2) ? IPPORT_NNTP : atoi(argv[1]);
  1166.  
  1167.     Snntp = socket(AF_INET,SOCK_STREAM,0);
  1168.     bind(Snntp,(char *)&lsocket,sizeof(lsocket));
  1169.     listen(Snntp,1);
  1170.  
  1171.     for(;;){
  1172.         if((s = accept(Snntp,NULLCHAR,(int *)NULL)) == -1)
  1173.             break;    /* Service is shutting down */
  1174.  
  1175.         if(availmem() < Memthresh){
  1176.             usputs(s,lowmem);
  1177.             shutdown(s,1);
  1178.         } else {
  1179.             sockmode(s,SOCK_ASCII);
  1180.             /* Spawn a server */
  1181.             newproc("NNTP server",4048,nntpserv,s,NULL,NULL,0);
  1182.         }
  1183.     }
  1184.     return 0;
  1185. }
  1186.  
  1187. /* Shutdown NNTP service (existing connections are allowed to finish) */
  1188. int
  1189. nntp0(argc,argv,p)
  1190. int argc;
  1191. char *argv[];
  1192. void *p;
  1193. {
  1194.     close_s(Snntp);
  1195.     Snntp = -1;
  1196.     return 0;
  1197. }
  1198.  
  1199. #endif /* NNTP */
  1200.